<html><head><meta charset="utf-8"/><title>双向绑定</title></head><body><h1>双向绑定</h1><div class="x-wiki-content x-main-content">
 <p>
  单向绑定非常简单，就是把Model绑定到View，当我们用JavaScript代码更新Model时，View就会自动更新。
 </p>
 <p>
  有单向绑定，就有双向绑定。如果用户更新了View，Model的数据也自动被更新了，这种情况就是双向绑定。
 </p>
 <p>
  什么情况下用户可以更新View呢？填写表单就是一个最直接的例子。当用户填写表单时，View的状态就被更新了，如果此时MVVM框架可以自动更新Model的状态，那就相当于我们把Model和View做了双向绑定：
 </p>
 <p>
  <img alt="mvvm-2way-binding" data-src="/files/attachments/1109527642503264/l" src="https://www.liaoxuefeng.com/files/attachments/1109527642503264/l"/>
 </p>
 <p>
  在浏览器中，当用户修改了表单的内容时，我们绑定的Model会自动更新：
 </p>
 <p>
  <img alt="mvvm-form" data-src="/files/attachments/1109527763830016/l" src="https://www.liaoxuefeng.com/files/attachments/1109527763830016/l"/>
 </p>
 <p>
  在Vue中，使用双向绑定非常容易，我们仍然先创建一个VM实例：
 </p>
 <pre><code>$(function () {
    var vm = new Vue({
        el: '#vm',
        data: {
            email: '',
            name: ''
        }
    });
    window.vm = vm;
});
</code></pre>
 <p>
  然后，编写一个HTML FORM表单，并用
  <code>
   v-model
  </code>
  指令把某个
  <code>
   &lt;input&gt;
  </code>
  和Model的某个属性作双向绑定：
 </p>
 <pre><code>&lt;form id="vm" action="#"&gt;
    &lt;p&gt;&lt;input v-model="email"&gt;&lt;/p&gt;
    &lt;p&gt;&lt;input v-model="name"&gt;&lt;/p&gt;
&lt;/form&gt;
</code></pre>
 <p>
  我们可以在表单中输入内容，然后在浏览器console中用
  <code>
   window.vm.$data
  </code>
  查看Model的内容，也可以用
  <code>
   window.vm.name
  </code>
  查看Model的
  <code>
   name
  </code>
  属性，它的值和FORM表单对应的
  <code>
   &lt;input&gt;
  </code>
  是一致的。
 </p>
 <p>
  如果在浏览器console中用JavaScript更新Model，例如，执行
  <code>
   window.vm.name='Bob'
  </code>
  ，表单对应的
  <code>
   &lt;input&gt;
  </code>
  内容就会立刻更新。
 </p>
 <p>
  除了
  <code>
   &lt;input type="text"&gt;
  </code>
  可以和字符串类型的属性绑定外，其他类型的
  <code>
   &lt;input&gt;
  </code>
  也可以和相应数据类型绑定：
 </p>
 <p>
  多个checkbox可以和数组绑定：
 </p>
 <pre><code>&lt;label&gt;&lt;input type="checkbox" v-model="language" value="zh"&gt; Chinese&lt;/label&gt;
&lt;label&gt;&lt;input type="checkbox" v-model="language" value="en"&gt; English&lt;/label&gt;
&lt;label&gt;&lt;input type="checkbox" v-model="language" value="fr"&gt; French&lt;/label&gt;
</code></pre>
 <p>
  对应的Model为：
 </p>
 <pre><code>language: ['zh', 'en']
</code></pre>
 <p>
  单个checkbox可以和boolean类型变量绑定：
 </p>
 <pre><code>&lt;input type="checkbox" v-model="subscribe"&gt;
</code></pre>
 <p>
  对应的Model为：
 </p>
 <pre><code>subscribe: true; // 根据checkbox是否选中为true/false
</code></pre>
 <p>
  下拉框
  <code>
   &lt;select&gt;
  </code>
  绑定的是字符串，但是要注意，绑定的是value而非用户看到的文本：
 </p>
 <pre><code>&lt;select v-model="city"&gt;
    &lt;option value="bj"&gt;Beijing&lt;/option&gt;
    &lt;option value="sh"&gt;Shanghai&lt;/option&gt;
    &lt;option value="gz"&gt;Guangzhou&lt;/option&gt;
&lt;/select&gt;
</code></pre>
 <p>
  对应的Model为：
 </p>
 <pre><code>city: 'bj' // 对应option的value
</code></pre>
 <p>
  双向绑定最大的好处是我们不再需要用jQuery去查询表单的状态，而是直接获得了用JavaScript对象表示的Model。
 </p>
 <h3>
  处理事件
 </h3>
 <p>
  当用户提交表单时，传统的做法是响应
  <code>
   onsubmit
  </code>
  事件，用jQuery获取表单内容，检查输入是否有效，最后提交表单，或者用AJAX提交表单。
 </p>
 <p>
  现在，获取表单内容已经不需要了，因为双向绑定直接让我们获得了表单内容，并且获得了合适的数据类型。
 </p>
 <p>
  响应
  <code>
   onsubmit
  </code>
  事件也可以放到VM中。我们在
  <code>
   &lt;form&gt;
  </code>
  元素上使用指令：
 </p>
 <pre><code>&lt;form id="vm" v-on:submit.prevent="register"&gt;
</code></pre>
 <p>
  其中，
  <code>
   v-on:submit="register"
  </code>
  指令就会自动监听表单的
  <code>
   submit
  </code>
  事件，并调用
  <code>
   register
  </code>
  方法处理该事件。使用
  <code>
   .prevent
  </code>
  表示阻止事件冒泡，这样，浏览器不再处理
  <code>
   &lt;form&gt;
  </code>
  的
  <code>
   submit
  </code>
  事件。
 </p>
 <p>
  因为我们指定了事件处理函数是
  <code>
   register
  </code>
  ，所以需要在创建VM时添加一个
  <code>
   register
  </code>
  函数：
 </p>
 <pre><code>var vm = new Vue({
    el: '#vm',
    data: {
        ...
    },
    methods: {
        register: function () {
            // 显示JSON格式的Model:
            alert(JSON.stringify(this.$data));
            // TODO: AJAX POST...
        }
    }
});
</code></pre>
 <p>
  在
  <code>
   register()
  </code>
  函数内部，我们可以用AJAX把JSON格式的Model发送给服务器，就完成了用户注册的功能。
 </p>
 <p>
  使用CSS修饰后的页面效果如下：
 </p>
 <p>
  <img alt="mvvm-form" data-src="/files/attachments/1109532154195168/l" src="https://www.liaoxuefeng.com/files/attachments/1109532154195168/l"/>
 </p>
 <h3>
  参考源码
 </h3>
 <p>
  <a href="https://github.com/michaelliao/learn-javascript/tree/master/samples/node/web/vue/form-vue">
   form-vue
  </a>
 </p>
</div>
</body></html>